package com.ec.auth.authen;


import com.ec.auth.common.enums.RespResultEnum;
import com.ec.auth.dto.UserLoginDTO;
import com.ec.common.constant.RedisKeyConstant;
import com.ec.common.constant.TokenConstant;
import com.ec.core.common.core.api.Result;
import com.ec.core.common.core.secure.AuthInfo;
import com.ec.core.common.core.secure.TokenInfo;
import com.ec.core.common.exception.BizException;
import com.ec.core.common.utils.HttpServletUtil;
import com.ec.core.redis.utils.CoreRedisUtil;
import com.ec.core.secure.utils.JwtUtil;
import com.ec.system.api.modules.sys.dto.SysUserLoginDTO;
import com.ec.system.api.modules.sys.feign.ISysUserFeign;
import com.ec.system.api.modules.sys.vo.SysRoleVO;
import com.ec.system.api.modules.sys.vo.SysUserLoginVO;
import com.google.common.collect.Maps;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @description: 账号密码授权
 * @author: Eric Lee
 * @time: 2021/6/7 19:43
 */
@Component
public class PasswordAuthen implements IAuthen {
    @Resource
    private ISysUserFeign sysUserClient;

    public static final String GRANT_TYPE = "password";

    @Override
    public AuthInfo authentication(UserLoginDTO userLoginDTO) {
        String key = String.format(RedisKeyConstant.UserLogin.CAPTCHA_KEY, userLoginDTO.getCodeKey());
        String code = CoreRedisUtil.get(key);
        if (!userLoginDTO.getCaptcha().equalsIgnoreCase(code)) {
            CoreRedisUtil.del(key);
            throw new BizException(RespResultEnum.CAPTCHA_VERIFICATION_ERROR);
        }
        if(CoreRedisUtil.hasKey(key)){
            CoreRedisUtil.del(key);
        }
        SysUserLoginDTO loginDTO = new SysUserLoginDTO();
        loginDTO.setUserAccount(userLoginDTO.getAccount());
        loginDTO.setUserPassword(userLoginDTO.getPassword());
        Result<SysUserLoginVO> sysUserLoginBoResult = sysUserClient.sysUserLogin(loginDTO);
        if (!sysUserLoginBoResult.isSuccess()) {
            throw new BizException(sysUserLoginBoResult);
        }
        SysUserLoginVO vo = sysUserLoginBoResult.getObj();
        if (StringUtils.isBlank(vo.getUserAvatar())) {
            vo.setUserAvatar(TokenConstant.DEFAULT_AVATAR);
        }
        AuthInfo authInfo = new AuthInfo();
        Map<String, Object> claims = buildJwtClaims(vo);
        TokenInfo tokenInfo = JwtUtil.createJwt(claims, RedisKeyConstant.Global.TOKEN_EXPIRE);
        authInfo.setAccessToken(tokenInfo.getToken());
        authInfo.setExpire(tokenInfo.getExpire());
        authInfo.setUserInfo(vo);
        //保存到缓存
        CoreRedisUtil.set(String.format(RedisKeyConstant.Global.TOKEN_KEY, vo.getUserId()),
                tokenInfo.getToken(), RedisKeyConstant.Global.TOKEN_EXPIRE, TimeUnit.MILLISECONDS);
        //保存IP
        CoreRedisUtil.set(String.format(RedisKeyConstant.Global.USER_IP_KEY, vo.getUserId()),
                HttpServletUtil.getIpAddr(), RedisKeyConstant.Global.TOKEN_EXPIRE, TimeUnit.MILLISECONDS);
        return authInfo;
    }

    private Map<String, Object> buildJwtClaims(SysUserLoginVO sysUserLoginVO) {
        Map<String, Object> claims = Maps.newHashMap();
        //签发人userId
        claims.put(Claims.AUDIENCE, sysUserLoginVO.getUserId());
        claims.put(Claims.ISSUER, sysUserLoginVO.getUserId());
        claims.put("userAccount", sysUserLoginVO.getUserAccount());
        claims.put("userName", sysUserLoginVO.getUserName());
        claims.put("userId", sysUserLoginVO.getUserId());
        claims.put("userMobile", sysUserLoginVO.getUserMobile());
        claims.put("deptId", sysUserLoginVO.getDeptId());
        claims.put("tenantId", sysUserLoginVO.getTenantId());
        claims.put("tenantCode", sysUserLoginVO.getTenantCode());
        claims.put("postId", sysUserLoginVO.getPostId());
        claims.put("userSex", sysUserLoginVO.getUserSex());
        claims.put("roleCodes", sysUserLoginVO.getRoles().stream().map(SysRoleVO::getRoleCode).collect(Collectors.toList()));
        claims.put("roleIds", sysUserLoginVO.getRoles().stream().map(SysRoleVO::getRoleId).collect(Collectors.toList()));
        return claims;
    }
}
